package cz.data.domain.masterdata.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import cz.data.common.exception.DataException;
import cz.data.common.support.db.DbProperty;
import cz.data.common.support.db.DbType;
import cz.data.common.support.db.driver.DataOperation;
import cz.data.common.utils.SecurityUtil;
import cz.data.domain.driver.rpc.ElasticsearchDriverFeign;
import cz.data.domain.driver.rpc.IDriverFeign;
import cz.data.domain.driver.rpc.JdbcDriverFeign;
import cz.data.domain.driver.rpc.MongoDriverFeign;
import cz.data.domain.masterdata.model.dto.ModelData;
import cz.data.domain.masterdata.model.entity.ModelEntity;
import cz.data.domain.masterdata.model.query.ModelDataQuery;
import cz.data.domain.masterdata.service.ModelDataService;
import cz.data.domain.masterdata.service.ModelService;
import cz.data.domain.masterdata.utils.ModelUtils;
import cz.data.domain.metadata.model.MetadataUtil;
import cz.data.domain.metadata.rpc.MetadataSourceFeign;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
public class ModelDataServiceImpl implements ModelDataService {

    @Resource
    ModelService modelService;
    @Resource
    MetadataSourceFeign metadataSourceFeign;
    @Resource
    JdbcDriverFeign jdbcDriverFeign;
    @Resource
    ElasticsearchDriverFeign elasticsearchDriverFeign;
    @Resource
    MongoDriverFeign mongoDriverFeign;

    private static final String DEFAULT_PRIMARY_KEY = "id";
    private static final String DEFAULT_CREATE_BY = "create_by";
    private static final String DEFAULT_CREATE_TIME = "create_time";
    private static final String DEFAULT_CREATE_DEPT = "create_dept";
    private static final String DEFAULT_UPDATE_BY = "update_by";
    private static final String DEFAULT_UPDATE_TIME = "update_time";

    private DbProperty getDataSource(String modelId) {
        ModelEntity model = modelService.getModelById(modelId);
        return Optional.ofNullable(model.getSourceId())
                .map(metadataSourceFeign::getMetadataSourceById)
                .map(MetadataUtil::dbProperty)
                .orElse(null);
    }

    @Override
    public IPage<JSONObject> getPageModelDatas(ModelDataQuery modelDataQuery) {
        String modelId = modelDataQuery.getMid();
        ModelEntity model = Optional.ofNullable(modelId)
                .map(modelService::getModelById)
                .orElseThrow(() -> new DataException("数据库表为空"));
        DbProperty property = getDataSource(modelId);
        List<String> columns = modelDataQuery.getColumns();
        columns.add(0, DEFAULT_PRIMARY_KEY);
        columns.add(1, DEFAULT_CREATE_TIME);
        IDriverFeign driverFeign = getDriverFeign(property.getDbType());
        DataOperation operation = new DataOperation();
        operation.setSource(property.getId());
        operation.setTable(ModelUtils.dbTable(model));
        operation.setFields(columns);
        operation.setConditions(modelDataQuery.getConditions());
        operation.setPageNum(modelDataQuery.getPageNum());
        operation.setPageSize(modelDataQuery.getPageSize());
        return driverFeign.getPageData(operation);
    }

    @Override
    public void addModelData(ModelData modelData) {
        String modelId = modelData.getMid();
        ModelEntity model = Optional.ofNullable(modelId)
                .map(modelService::getModelById)
                .orElseThrow(() -> new DataException("数据库表为空"));
        String tableName = model.getModelPhysicalTable();
        modelData.setTableName(tableName);
        JSONObject datas = modelData.getRow();
        datas.put(DEFAULT_PRIMARY_KEY, IdWorker.getIdStr());
        datas.put(DEFAULT_CREATE_BY, SecurityUtil.getUserId());
        datas.put(DEFAULT_CREATE_TIME, LocalDateTime.now());
        datas.put(DEFAULT_CREATE_DEPT, SecurityUtil.getUserDeptId());
        datas.put(DEFAULT_UPDATE_BY, SecurityUtil.getUserId());
        datas.put(DEFAULT_UPDATE_TIME, LocalDateTime.now());
        DbProperty property = getDataSource(modelId);
        IDriverFeign driverFeign = getDriverFeign(property.getDbType());
        DataOperation operation = new DataOperation();
        operation.setSource(property.getId());
        operation.setTable(ModelUtils.dbTable(model));
        operation.setData(datas);
        driverFeign.insertData(operation);
    }

    @Override
    public void updateModelData(ModelData modelData) {
        String modelId = modelData.getMid();
        DbProperty property = getDataSource(modelId);
        ModelEntity model = Optional.ofNullable(modelId)
                .map(modelService::getModelById)
                .orElseThrow(() -> new DataException("数据库表为空"));
        String tableName = model.getModelPhysicalTable();
        modelData.setTableName(tableName);
        JSONObject row = modelData.getRow();
        if (Objects.isNull(row)) {
            row = new JSONObject();
        }
        row.putIfAbsent(DEFAULT_PRIMARY_KEY, modelData.getId());
        row.put(DEFAULT_UPDATE_BY, SecurityUtil.getUserId());
        row.put(DEFAULT_UPDATE_TIME, LocalDateTime.now());
        IDriverFeign driverFeign = getDriverFeign(property.getDbType());
        DataOperation operation = new DataOperation();
        operation.setSource(property.getId());
        operation.setTable(ModelUtils.dbTable(model));
        operation.setData(row);
        driverFeign.updateData(operation);
    }

    @Override
    public void delModelData(ModelData modelData) {
        String modelId = modelData.getMid();
        ModelEntity model = Optional.ofNullable(modelId)
                .map(modelService::getModelById)
                .orElseThrow(() -> new DataException("数据库表为空"));
        DbProperty property = getDataSource(modelId);
        String tableName = model.getModelPhysicalTable();
        modelData.setTableName(tableName);
        JSONObject row = modelData.getRow();
        if (Objects.isNull(row)) {
            row = new JSONObject();
        }
        row.putIfAbsent(DEFAULT_PRIMARY_KEY, modelData.getId());
        IDriverFeign driverFeign = getDriverFeign(property.getDbType());
        DataOperation operation = new DataOperation();
        operation.setSource(property.getId());
        operation.setTable(ModelUtils.dbTable(model));
        operation.setData(row);
        driverFeign.removeData(operation);
    }

    @Override
    public JSONObject getModelDataById(ModelData modelData) {
        String modelId = modelData.getMid();
        DbProperty property = getDataSource(modelId);
        ModelEntity model = Optional.ofNullable(modelId)
                .map(modelService::getModelById)
                .orElseThrow(() -> new DataException("数据库表为空"));
        String tableName = model.getModelPhysicalTable();
        modelData.setTableName(tableName);
        JSONObject row = modelData.getRow();
        if (Objects.isNull(row)) {
            row = new JSONObject();
        }
        row.putIfAbsent(DEFAULT_PRIMARY_KEY, modelData.getId());
        IDriverFeign driverFeign = getDriverFeign(property.getDbType());
        DataOperation operation = new DataOperation();
        operation.setSource(property.getId());
        operation.setTable(ModelUtils.dbTable(model));
        operation.setData(row);
        return driverFeign.getDataById(operation);
    }

    private IDriverFeign getDriverFeign(String dbType) {
        if (DbType.ELASTICSEARCH.getDb().equals(dbType)) {
            return elasticsearchDriverFeign;
        } else if (DbType.MONGODB.getDb().equals(dbType)) {
            return mongoDriverFeign;
        } else {
            return jdbcDriverFeign;
        }
    }
}
